/*
 * @Description: 霍纳规则
 * @Version: 
 * @Author: Weixin Zhu
 * @Date: 2020-12-11 17:41:43
 * @LastEditors: Weixin Zhu
 * @LastEditTime: 2020-12-11 20:08:55
 */
package com.zwx.algorithms.basic;

import com.zwx.algorithms.constant.AlgorithmsConstant;
import com.zwx.algorithms.pub.util.AlgorithmsUtils;
import com.zwx.algorithms.pub.util.LogUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.StopWatch;

public class HornerRule {
    static final Logger log = LoggerFactory.getLogger(InsertionSort.class);
    Integer[] array = null;
    Integer x = 0;
    int len = 0;
    Integer n = 0;
    int step = 0;

    public HornerRule(Integer[] array, Integer x) {
        this.array = array;
        this.x = x;
        this.len = array.length;
        this.n = array.length;
    }

    public int hornerRule() {
        int y = 0;
        for (int i = 0; i < len; i++) {
            y = array[i] + x * y;
            if (AlgorithmsUtils.needShowStep(len)) {
                log.debug("index :{},y:{},a:{},x:{}", (++step), y, array[i], x);
            }
        }
        return y;
    }

    /**
     * 超过5000个元素就可能StackOverflowError
     *   Java里每个线程都有一个栈空间（栈内存），可以通过JVM参数-Xss256k来配置线程栈空间大小；
     *   而线程栈空间里还有栈帧的概念，线程上每调用一个方法都会压入一个栈帧（栈帧里存储该方法里的栈变量），
     *     比如主线程执行main方法，那么main方法就是主线程的一个栈帧，在main方法里再调用test()方法，则主线程又会压入新的栈帧来对应test()方法；
     *     当执行完毕方法返回后，比如test()方法执行完毕，那么线程会将对应的栈帧弹出，即释放由该方法创建的变量占用的栈内存；
     * @return
     */
    Integer exec() {
        ++step;
        n--;
        if (AlgorithmsUtils.needShowStep(len)) {
            log.debug("index :{},y:{},a:{},x:{}", (step));
        }
        if (n == 0) {
            return array[0];
        } else if (n > 0) {
            try {
                return array[n] + x * exec();
            } catch (Throwable e) {
                e.printStackTrace();
                System.out.println(e);
                System.out.println("index :{},n:{},a:{}.s" + (step) + "," + n + "," + array[n]);
                return -1;
            }
        }

        return null;

    }

    void reset() {
        this.step = 0;
    }

    public static void main(String[] args) {
        LogUtils.resetLogLevel(log, org.slf4j.event.Level.DEBUG);
        Integer[] originArray = null;
        Integer result = null;
        originArray = AlgorithmsUtils.generateRandomArray(AlgorithmsConstant.MAX_VALUE);
        StopWatch sw = DateUtil.createStopWatch();
        HornerRule rule = new HornerRule(originArray, 5);
        // 循环
        sw.start();
        result = rule.hornerRule();
        sw.stop();
        log.info("result1:{},cost time:{}", result, sw.getLastTaskTimeMillis());
        rule.reset();
        // 递归
        sw.start();
        result = rule.exec();
        sw.stop();
        log.info("result2:{},cost time:{}", result, sw.getLastTaskTimeMillis());

        log.info(sw.prettyPrint());
        System.out.println(Integer.MAX_VALUE);
    }
}
